package com.example.aop.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理和AOP
 * @author: qilongxin
 * @date: 2021/8/18 14:07
 */
public class ProxyTest2 {
    public static void main(String[] args) throws Throwable {
        Animal target = new Dog();
        Animal animal = (Animal) AnimalProxyFactory.getProxy(target);
        animal.info();
        animal.description();
    }
}


interface Animal {
    void info();
    void description();
}

class Dog implements Animal {
    @Override
    public void info() {
        System.out.println("这是一只狗。");
    }

    @Override
    public void description() {
        System.out.println("狗奔跑速度挺快。");
    }
}

class AnimalUtil {
    /**
     * 前置拦截方法
     */
    public void beforeIntercept() {
        System.out.println("====AnimalUtil前置拦截方法====");
    }
    /**
     * 后置拦截方法
     */
    public void afterIntercept() {
        System.out.println("====AnimalUtil后置拦截方法====\n");
    }
}

class AnimalInvocationHandler implements InvocationHandler {
    /**
     * 目标对象
     */
    private Object target;
    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        AnimalUtil au = new AnimalUtil();
        // 调用前置方法
        au.beforeIntercept();
        // 通过反射执行method方法，回调了目标对象的原有方法
        Object result = method.invoke(target, args);
        // 调用后置方法
        au.afterIntercept();
        return result;
    }
}

class AnimalProxyFactory {
    /**
     * 定义代理工厂，为目标对象target生成动态代理对象proxy
     *
     * JDK动态代理主要涉及到java.lang.reflect包中的两个类：Proxy和InvocationHandler。
     * InvocationHandler是一个接口，通过实现该接口定义横切逻辑，并通过反射机制调用目标类的代码，动态将横切逻辑和业务逻辑编制在一起。
     * Proxy利用InvocationHandler动态创建一个符合某一接口的实例，生成目标类的代理对象。
     *
     */
    public static Object getProxy(Object target) throws Throwable {
        AnimalInvocationHandler handler = new AnimalInvocationHandler();
        handler.setTarget(target);
        // 返回代理对象
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
    }
}


